using System;
using System.Collections.Generic;
using ContentRenderingApi.NodeData;
using ContentRenderingApi.Exceptions;

namespace ContentRenderingApi.Node
{
    /// <summary/>
    internal abstract class AbstractContainerNode : AbstractNode
    {
        private List<AbstractNode> _children;

        /// <summary/>
        internal AbstractContainerNode(AbstractNode parent) : base(parent)
        {
            this._children = new List<AbstractNode>();
        }

        /// <summary/>
        internal override AbstractNode AddParentSubstitutionTag(int level)
        {
            AbstractNode node = new SubstitutionTagNode(this, new ParentNodeData(level));

            // record the object
            this._children.Add(node);

            return node;
        }

        /// <summary/>
        internal override AbstractNode AddParentTransparentTag(int level)
        {
            AbstractNode node = new TransparentTagNode(this, new ParentNodeData(level));

            // record the object
            this._children.Add(node);

            return node;
        }

        /// <summary/>
        internal override AbstractNode AddParentIfTag(int level)
        {
            AbstractNode node = new IfTagNode(this, new ParentNodeData(level));

            // record the object
            this._children.Add(node);

            return node;
        }

        /// <summary/>
        internal override AbstractNode AddParentIfNotTag(int level)
        {
            AbstractNode node = new IfNotTagNode(this, new ParentNodeData(level));

            // record the object
            this._children.Add(node);

            return node;
        }

        /// <summary/>
        internal override void AddParentOutputTag(int level)
        {
            AbstractNode node = new OutputTagNode(this, new ParentNodeData(level));

            // record the object
            this._children.Add(node);
        }

        /// <summary/>
        internal override AbstractNode AddChildSubstitutionTag(string name)
        {
            AbstractNode node = new SubstitutionTagNode(this, new ChildNodeData(name));

            // record the object
            this._children.Add(node);

            return node;
        }

        /// <summary/>
        internal override AbstractNode AddChildTransparentTag(string name)
        {
            AbstractNode node = new TransparentTagNode(this, new ChildNodeData(name));

            // record the object
            this._children.Add(node);

            return node;
        }

        /// <summary/>
        internal override AbstractNode AddChildIfTag(string name)
        {
            AbstractNode node = new IfTagNode(this, new ChildNodeData(name));

            // record the object
            this._children.Add(node);

            return node;
        }

        /// <summary/>
        internal override AbstractNode AddChildIfNotTag(string name)
        {
            AbstractNode node = new IfNotTagNode(this, new ChildNodeData(name));

            // record the object
            this._children.Add(node);

            return node;
        }

        /// <summary/>
        internal override void AddChildOutputTag(string name)
        {
            AbstractNode node = new OutputTagNode(this, new ChildNodeData(name));

            // record the object
            this._children.Add(node);
        }

        /// <summary/>
        internal override AbstractNode AddRootSubstitutionTag(string name)
        {
            AbstractNode node = new SubstitutionTagNode(this, new RootNodeData(name));

            // record the object
            this._children.Add(node);

            return node;
        }

        /// <summary/>
        internal override AbstractNode AddRootTransparentTag(string name)
        {
            AbstractNode node = new TransparentTagNode(this, new RootNodeData(name));

            // record the object
            this._children.Add(node);

            return node;
        }

        /// <summary/>
        internal override AbstractNode AddRootIfTag(string name)
        {
            AbstractNode node = new IfTagNode(this, new RootNodeData(name));

            // record the object
            this._children.Add(node);

            return node;
        }

        /// <summary/>
        internal override AbstractNode AddRootIfNotTag(string name)
        {
            AbstractNode node = new IfNotTagNode(this, new RootNodeData(name));

            // record the object
            this._children.Add(node);

            return node;
        }

        /// <summary/>
        internal override void AddRootOutputTag(string name)
        {
            AbstractNode node = new OutputTagNode(this, new RootNodeData(name));

            // record the object
            this._children.Add(node);
        }

        /// <summary/>
        internal override void AddContent(string content)
        {
            AbstractNode node = new ContentNode(this, content);

            // record the object
            this._children.Add(node);
        }
        
        /// <summary/>
        internal override bool IsContent()
        {
            return false;
        }

        /// <summary/>
        internal override string Content
        {
            get { throw new NodeDoesNotHaveContentException(); }
        }

        /// <summary/>
        internal override IEnumerator<AbstractNode> FetchChildNodes()
        {
            return this._children.GetEnumerator();
        }
    }
}
